﻿#ifndef __LOG_H__
#define __LOG_H__

#include "Common.h"
#ifdef SUPPORT_LOG

#include "ostrbuf.h"
#include "ILogger.h"
#include "StringConv.h"
#include "Mutex.h"

#include <time.h>
#include <iostream>
#include <fstream>

    /**
        Log设计要点：
        1、方便，仅几个宏直接使用；
        2、基于类型安全，取消诸如 printf 的不安全格式；
        3、输出信息可重定向；
        4、线程安全；
        5、支持输出级别；
    */
   namespace sky
   {


        // Appender 输出目标

        // 输出到控制台
        class ConsoleAppender : public LogAppender
        {
        public:
            virtual void Log(const char * msg, const char * time, LogLevel level);
        };

        // 输出到html
        class FileAppender : public LogAppender
        {
            std::ofstream m_File;

        public:
            FileAppender() {};
            ~FileAppender();

            bool create(const char * filename, bool bWrite);
            virtual void Log(const char * msg, const char * time, LogLevel level);
        };


        class Logger
        {
        public:
            Logger();
            ~Logger();

            bool create(int level, bool hasTime);
            void close();
            void output(const char * msg, LogLevel level, const char * file, int line);
            void swaplist();
            void output_outlist();

            void setLogerLuaPath(const std::string& path);
            int getLevel() const;
            int setLevel(int level);
            bool setHasTime(bool hasTime);
            bool setLimitFrequency(bool limitFrequency);
            bool hasLimitFrequency();
            size_t setMessageThreshold(size_t threshold);
            size_t getMessageThreshold() const;
            void registerAppender(LogAppender * appender);
            void unRegisterAppender(LogAppender * appender);


        public:
            static DWORD WINAPI LoggerProc(LPVOID arg);



        public:
            struct _MSG
            {
                std::string msg;
                time_t time;
                LogLevel level;
            };

            typedef std::list<_MSG>             MsgList;
            typedef std::list<LogAppender*>     AppenderList;

            // 输入目标列表
            AppenderList    m_lstAppenders;

            //输出级别
            int level;
            // 是否显示时间
            bool hasTime;
            // 是否显示文件行号
            bool hasFileLine;
            // 是否限制同一个位置的输出频率
            bool limitFrequency;

            // 退出标志
            volatile bool isExit;
            // 互斥体
            Mutex mutex;
            // 线程句柄
            HANDLE hThread;
            // 事件句柄
            HANDLE hEvent;
            // 消息列表1
            MsgList  msgs1;
            // 消息队列2
            MsgList  msgs2;
            // 用于输入的列表
            MsgList * inList;
            // 用于输出的列表
            MsgList * outList;
            // 是否需要移除处理完的节点
            bool clearOutList;
            // 队列中容纳最大的消息数
            size_t threshold;
            std::string luapath;
        };


        // 全局Logger
        Logger * gLogger = 0;

        
        // 创建全局logger
        SKY_API void createLogger(int level = LogLevel_All, bool hasTime = true, bool threadSafe = true);
        // 关闭全局logger
        SKY_API void closeLogger();
        // 设置全局logger日志等级
        SKY_API int setLoggerLevel(int level);
        // 获取全局logger日志等级
        SKY_API int getLoggerLevel();
        // 设置全局logger是否显示时间
        SKY_API bool setLoggerHasTime(bool hasTime);
        // 设置全局logger是否显示文件行数
        SKY_API bool setLoggerHasFileLine(bool hasFileLine);
        // 设置全局logger是否开启输出频率控制
        SKY_API bool setLoggerLimitFrequency(bool limitFrequency);
        // 获取全局logger是否开启输出频率控制
        SKY_API bool hasLoggerLimitFrequency();
        // 设置全局logger消息队列最大容量
        SKY_API size_t setTraceMessageThreshold(size_t threshold);
        // 获取全局logger消息队列最大容量
        SKY_API size_t getTraceMessageThreshold();

        // 设置lua的路径
        SKY_API void setTraceLuaPath(const char* path);

        // 向全局logger添加appender
        SKY_API void registerLogAppender(LogAppender * appender);

        // 向全局logger删除appender
        SKY_API void unRegisterLogAppender(LogAppender * appender);

        //输出日志
        SKY_API void output(const char * msg, LogLevel level, const char * file, int line);

        // 给全局logger添加一个ConsoleAppender
        SKY_API LogAppender * output2Console(int level = LogLevel_All, bool hasTime = false);

        // 给全局logger添加一个FileAppender
        SKY_API LogAppender * output2File(const char * filename = NULL, int level = LogLevel_All, bool hasTime = false);

        // loglevel 转换成字符串
        SKY_API const char * LogLevelToString(sky::LogLevel level);

   } // namespace sky


#define SKY_LOG_LEVEL_NAME(level) sky::LogLevelToString(level)

//
#define SKY_LOG_LEVEL(x, level, ln) \
    do {\
        if(sky::getLoggerLevel() && level) \
        {\
            sky::ostrbuf o_s_b;\
            o_s_b << SKY_LOG_LEVEL_NAME(level);\
            o_s_b << x;\
            o_s_b << ln;\
            sky::output(o_s_b.c_str(), level, __FILE__, __LINE__);\
        }\
    }while(0);

#define SKY_LOG_FMT_LEVEL(level, ln, x, ...) \
    do {\
        if(sky::getLoggerLevel() && level) \
        {\
            sky::ostrbuf o_s_b;\
            o_s_b << SKY_LOG_LEVEL_NAME(level);\
            o_s_b.add_format(x, __VA_ARGS__);\
            o_s_b << ln;\
            sky::output(o_s_b.c_str(), level, __FILE__, __LINE__);\
        }\
    }while(0);


 // 日志输出宏
#define Trace(x)            SKY_LOG_LEVEL(x, sky::LogLevel_Trace, "")
#define Warning(x)          SKY_LOG_LEVEL(x, sky::LogLevel_Warning, "")
#define Error(x)            SKY_LOG_LEVEL(x, sky::LogLevel_Error, "")
#define Emphasis(x)         SKY_LOG_LEVEL(x, sky::LogLevel_Emphasis, "")

#define TraceLn(x)          SKY_LOG_LEVEL(x, sky::LogLevel_Trace, "\n")
#define WarningLn(x)        SKY_LOG_LEVEL(x, sky::LogLevel_Warning, "\n")
#define ErrorLn(x)          SKY_LOG_LEVEL(x, sky::LogLevel_Error, "\n")
#define EmphasisLn(x)       SKY_LOG_LEVEL(x, sky::LogLevel_Emphasis, "\n")


#define Trace_FMT(fmtx, ...)            SKY_LOG_FMT_LEVEL(sky::LogLevel_Trace, "", fmtx, __VA_ARGS__)
#define Warning_FMT(fmtx, ...)          SKY_LOG_FMT_LEVEL(sky::LogLevel_Warning, "", fmtx, __VA_ARGS__)
#define Error_FMT(fmtx, ...)            SKY_LOG_FMT_LEVEL(sky::LogLevel_Error, "", fmtx, __VA_ARGS__)
#define Emphasis_FMT(fmtx, ...)         SKY_LOG_FMT_LEVEL(sky::LogLevel_Emphasis, "", fmtx, __VA_ARGS__)
   
#define TraceLn_FMT(fmtx, ...)            SKY_LOG_FMT_LEVEL(sky::LogLevel_Trace, "\n", fmtx, __VA_ARGS__)
#define WarningLn_FMT(fmtx, ...)          SKY_LOG_FMT_LEVEL(sky::LogLevel_Warning, "\n", fmtx, __VA_ARGS__)
#define ErrorLn_FMT(fmtx, ...)            SKY_LOG_FMT_LEVEL(sky::LogLevel_Error, "\n", fmtx, __VA_ARGS__)
#define EmphasisLn_FMT(fmtx, ...)         SKY_LOG_FMT_LEVEL(sky::LogLevel_Emphasis, "\n", fmtx, __VA_ARGS__)

#else // #ifdef SUPPORT_LOG

#endif // for SUPPORT_LOG

#endif // for __LOG_H__